import os, sys
class_folder = os.path.join(os.getcwd(),'classes')
if class_folder not in sys.path:
    sys.path.insert(0,class_folder)

from wall import *
from cell_visuals import *

# Constants - The Walls collection in this class represents walls
# in the 4 cardinal directions. It's easier to refer to them by name
NORTH = 0
SOUTH = 1
EAST  = 2
WEST  = 3

class MazeCell(object):
    ''' A Maze is made up of a grid of cells that each have walls. This class
    can render a cell using a CellVisuals object, and it keeps track of the
    cell's position and walls
    '''
    def __init__(self, x, y,
                 config,
                 walls = False
                 #backtrack = False,
                 #solution = False,
                 #border = False
                ):

        # The reason I did this instead of making the walls parameter default to
        # [True,True,True,True], is that in python the default values for the
        # parameters are evaluated at the time the code is first interpreted.
        # That means that if I set the default value to that list, python saves
        # the list, and then reuses it for every MazeCell. In other words,
        # instead of each cell having a list of walls, each cell will share the
        # same list of 4 walls. If I remove the NORTH wall, every cell in the
        # entire maze would lose its NORTH wall.
        #
        # Setting the value of the walls list inside the function, as I've done
        # here, avoids that whole problem
        if not walls:
            walls = [True,True,True,True]
        #

        # Not implemented - can be used for a future maze solver
        #self.backtrack = backtrack
        #self.solution = solution
        #self.border = border

        self.walls = walls
        self.x = x
        self.y = y

        self.config = config

    # Normally when you print a class as a string it prints something like
    # <MazeCell 234235345234> which isn't that useful. This built in function
    # override prints the x and y coordinates of the cell, plus the state of the
    # 4 walls
    def __str__(self):
        return '[%s,%s,%s,%s,%s,%s]' % self.x, self.y, self.walls[NORTH], self.walls[SOUTH], self.walls[EAST], self.walls[WEST]

    # This returns a CellVisuals which is responsible for the floor graphics
    def show(self):
        return CellVisuals(self.x, self.y, '', self.config) # str(self.x) + ',' + str(self.y), self.Config)

    # This function returns true if this cell still has all its walls. This is
    # useful in the maze generation algorithm (in the Maze class) because if a
    # cell has all its walls, it hasn't been visited yet
    def has_all_walls(self):
        # The list of walls is actually just 4 boolean values - True if there's
        # a wall, False if not.
        #
        # We're trying to check for existing walls, so we take the self.Walls
        # list, and we filter it. What filtering does is runs a given function
        # on each member of the list and if the function returns true, then the
        # member is added to the new list. If it's false, then it doesn't get
        # added. In this case, the function just checks whether the member is
        # true or not. If it's true (which means there's a wall present), then
        # it's added. There are 4 possible walls, so if the list has been
        # filtered to include only members that have walls, and there are still
        # 4 things on the list, then we know that all 4 walls are there. In
        # other words this cell "has all walls"
        #

        # Note: the filter object returns an "iterable," which means I can loop
        # over it if I want, but not get the length. The only thing I want in
        # this case is the length, so I convert the filter iterable to a list,
        # which has a len
        blocked = list(filter(lambda x: x, self.walls))
        return len(blocked) == 4

    # Remove the wall between this cell and the given neighboring cell
    def knock_out_wall(self, neighbor):
        # Find the relative position of the two cells, and remove the walls in
        # each cell that are facing each other
        if neighbor.x > self.x:
            self.walls[EAST] = False
            neighbor.walls[WEST] = False
        elif neighbor.x < self.x:
            self.walls[WEST] = False
            neighbor.walls[EAST] = False
        elif neighbor.y > self.y:
            self.walls[SOUTH] = False
            neighbor.walls[NORTH] = False
        elif neighbor.y < self.y:
            self.walls[NORTH] = False
            neighbor.walls[SOUTH] = False
